package com.haoxuer.discover.notice.data.service.impl;

import com.haoxuer.discover.config.data.dao.UserDao;
import com.haoxuer.discover.config.data.entity.User;
import com.haoxuer.discover.data.core.Finder;
import com.haoxuer.discover.data.core.Updater;
import com.haoxuer.discover.data.enums.StoreState;
import com.haoxuer.discover.data.page.Filter;
import com.haoxuer.discover.data.page.Order;
import com.haoxuer.discover.data.page.Page;
import com.haoxuer.discover.data.page.Pageable;
import com.haoxuer.discover.data.utils.FilterUtils;
import com.haoxuer.discover.notice.data.dao.UserNotificationDao;
import com.haoxuer.discover.notice.data.dao.UserNotificationMemberDao;
import com.haoxuer.discover.notice.data.dao.UserNotificationNumDao;
import com.haoxuer.discover.notice.data.dao.UserNotificationTimeDao;
import com.haoxuer.discover.notice.data.entity.UserNotification;
import com.haoxuer.discover.notice.data.entity.UserNotificationMember;
import com.haoxuer.discover.notice.data.entity.UserNotificationNum;
import com.haoxuer.discover.notice.data.entity.UserNotificationTime;
import com.haoxuer.discover.notice.data.enums.NotificationCategory;
import com.haoxuer.discover.notice.data.enums.NotificationState;
import com.haoxuer.discover.notice.data.service.UserNotificationService;
import com.haoxuer.discover.user.data.dao.UserInfoDao;
import com.haoxuer.discover.user.data.entity.UserInfo;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


/**
 * Created by imake on 2018年01月02日11:12:13.
 */


@Scope("prototype")
@Service
@Transactional
public class UserNotificationServiceImpl implements UserNotificationService {

  private UserNotificationDao dao;

  @Autowired
  private UserNotificationMemberDao notificationMemberDao;

  @Autowired
  private UserInfoDao userInfoDao;

  @Autowired
  private UserDao userDao;

  @Autowired
  UserNotificationTimeDao userNotificationTimeDao;

  @Autowired
  UserNotificationMemberDao userNotificationMemberDao;

  @Autowired
  UserNotificationNumDao userNotificationNumDao;


  @Override
  @Transactional
  public void updateNotices(Long user) {
    UserNotificationTime time = userNotificationTimeDao.findByUser(user);
    Finder findern = Finder.create();
    findern.append("from UserNotification u where u.addDate >:adddate and u.category=:category");
    findern.append(" and u.addDate <=:nowDate");
    findern.setParam("nowDate", new Date());
    findern.setParam("adddate", time.getLastDate());
    findern.setParam("category", NotificationCategory.pull);
    findern.append(" order by u.addDate asc ");
    findern.setMaxResults(20);
    List<UserNotification> ns = dao.find(findern);
    x(user, time, ns);
    userNotificationTimeDao.update(time);
  }

  @Override
  public void updateNoticesByNum(Long user) {
    UserNotificationNum num = userNotificationNumDao.findByUser(user);
    Finder findern = Finder.create();
    findern.append("from UserNotification u where u.id >:mid and u.category=:category");
    findern.setParam("mid", num.getMid());
    findern.setParam("category", NotificationCategory.pull);
    findern.append(" order by u.id asc ");
    findern.setMaxResults(20);
    List<UserNotification> ns = dao.find(findern);
    x(user, num, ns);
    userNotificationNumDao.update(num);
  }

  private void x(Long user, UserNotificationTime time, List<UserNotification> ns) {
    if (ns != null) {
      for (UserNotification userNotification : ns) {
        UserNotificationMember notificationMember = new UserNotificationMember();
        notificationMember.setNotification(userNotification);
        notificationMember.setState(NotificationState.unread);
        notificationMember.setUser(User.fromId(user));
        userNotificationMemberDao.add(notificationMember);
        if (time.getLastDate().before(userNotification.getAddDate())) {
          time.setLastDate(userNotification.getAddDate());
        }
      }
    }
  }

  private void x(Long user, UserNotificationNum time, List<UserNotification> ns) {
    if (ns != null) {
      for (UserNotification userNotification : ns) {
        UserNotificationMember notificationMember = new UserNotificationMember();
        notificationMember.setNotification(userNotification);
        notificationMember.setState(NotificationState.unread);
        notificationMember.setUser(User.fromId(user));
        userNotificationMemberDao.add(notificationMember);
        if (time.getMid() < userNotification.getId()) {
          time.setMid(userNotification.getId());
        }
      }
    }
  }

  @Override
  @Transactional
  public void updateNotices(Long user, Integer catalog) {
    UserNotificationTime time = userNotificationTimeDao.findByUser(user);
    Finder findern = Finder.create();
    findern.append("from UserNotification u where u.addDate >:adddate and u.category=:category and u.catalog.id=:catalog");
    findern.setParam("adddate", time.getLastDate());
    findern.setParam("catalog", catalog);
    findern.setParam("category", NotificationCategory.pull);

    findern.append(" order by u.addDate asc ");
    List<UserNotification> ns = dao.find(findern);
    x(user, time, ns);
    userNotificationTimeDao.update(time);
  }


  @Override
  @Transactional(readOnly = true)
  public UserNotification findById(Long id) {
    return dao.findById(id);
  }


  @Override
  @Transactional
  public UserNotification push(UserNotification bean) {
    bean.setStoreState(StoreState.normal);
    bean.setCategory(NotificationCategory.push);
    dao.save(bean);
    Integer total = 0;
    Pageable pageable = new Pageable();
    pageable.setPageSize(200);
    Page<User> page = userDao.page(pageable);
    total = total + sendUsers(bean, page);
    int totalPage = page.getTotalPages();
    for (int i = 2; i <= totalPage; i++) {
      pageable.setPageNumber(i);
      Page<User> pageData = userDao.page(pageable);
      total = total + sendUsers(bean, pageData);
    }
    bean.setNums(total);
    return bean;
  }

  @Override
  public UserNotification draft(UserNotification bean) {
    bean.setStoreState(StoreState.draft);
    return dao.save(bean);
  }

  private Integer sendUsers(UserNotification bean, Page<User> pagex) {
    Integer result = 0;
    List<User> userInfos = pagex.getContent();
    for (User userInfo : userInfos) {
      UserNotificationMember member = new UserNotificationMember();
      member.setNotification(bean);
      member.setState(NotificationState.unread);
      member.setUser(userInfo);
      notificationMemberDao.save(member);
      result++;
    }
    return result;
  }

  @Override
  public UserNotification pull(UserNotification bean) {
    bean.setCategory(NotificationCategory.pull);
    dao.save(bean);
    return bean;
  }

  @Override
  public UserNotification send(Long user, UserNotification bean) {
    bean.setStoreState(StoreState.normal);
    bean.setCategory(NotificationCategory.single);
    dao.save(bean);
    UserNotificationMember member = new UserNotificationMember();
    member.setNotification(bean);
    member.setState(NotificationState.unread);
    member.setUser(User.fromId(user));
    notificationMemberDao.save(member);
    bean.setNums(1);
    return bean;
  }

  @Override
  public UserNotification send(UserNotification bean, Long... users) {
    return dao.send(bean, users);
  }

  @Override
  @Transactional
  public UserNotification update(UserNotification bean) {
    Updater<UserNotification> updater = new Updater<UserNotification>(bean);
    return dao.updateByUpdater(updater);
  }

  @Override
  @Transactional
  public UserNotification deleteById(Long id) {
    UserNotification bean = dao.findById(id);
    if (bean!=null){
      bean.setStoreState(StoreState.draft);
    }
    return bean;
  }

  @Override
  @Transactional
  public UserNotification[] deleteByIds(Long[] ids) {
    UserNotification[] beans = new UserNotification[ids.length];
    for (int i = 0, len = ids.length; i < len; i++) {
      beans[i] = deleteById(ids[i]);
    }
    return beans;
  }


  @Autowired
  public void setDao(UserNotificationDao dao) {
    this.dao = dao;
  }

  @Override
  public Page<UserNotification> page(Pageable pageable) {
    return dao.page(pageable);
  }


  @Override
  public Page<UserNotification> page(Pageable pageable, Object search) {
    List<Filter> filters = FilterUtils.getFilters(search);
    if (filters != null) {
      pageable.getFilters().addAll(filters);
    }
    return dao.page(pageable);
  }

  @Override
  public List<UserNotification> list(int first, Integer size, List<Filter> filters, List<Order> orders) {
    return dao.list(first, size, filters, orders);
  }
}